//: C24:Recycle2.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 1999
// Copyright notice in Copyright.txt
// Chapter XX example w/ RTTI
#include "../purge.h"
#include <fstream>
#include <vector>
#include <typeinfo>
#include <cstdlib>
#include <ctime>
using namespace std;
ofstream out("recycle2.out");

class Trash
{
    float _weight;
public:
    Trash(float wt) : _weight(wt) {}
    virtual float value() const = 0;
    float weight() const {
        return _weight;
    }
    virtual ~Trash() {
        out << "~Trash()\n";
    }
};

class Aluminum : public Trash
{
    static float val;
public:
    Aluminum(float wt) : Trash(wt) {}
    float value() const {
        return val;
    }
    static void value(int newval) {
        val = newval;
    }
};

float Aluminum::val = 1.67;

class Paper : public Trash
{
    static float val;
public:
    Paper(float wt) : Trash(wt) {}
    float value() const {
        return val;
    }
    static void value(int newval) {
        val = newval;
    }
};

float Paper::val = 0.10;

class Glass : public Trash
{
    static float val;
public:
    Glass(float wt) : Trash(wt) {}
    float value() const {
        return val;
    }
    static void value(int newval) {
        val = newval;
    }
};

float Glass::val = 0.23;

// Sums up the value of the Trash in a bin:
template<class Container> void
sumValue(Container& bin, ostream& os)
{
    typename Container::iterator tally =
        bin.begin();
    float val = 0;
    while (tally != bin.end()) {
        val += (*tally)->weight() * (*tally)->value();
        os << "weight of "
        << typeid(*tally).name()
        << " = " << (*tally)->weight() << endl;
        tally++;
    }
    os << "Total value = " << val << endl;
}

int main()
{
    srand(time(0)); // Seed random number generator
    vector<Trash*> bin;
    // Fill up the Trash bin:
    for (int i = 0; i < 30; i++)
        switch (rand() % 3) {
        case 0 :
            bin.push_back(new Aluminum(rand() % 100));
            break;
        case 1 :
            bin.push_back(new Paper(rand() % 100));
            break;
        case 2 :
            bin.push_back(new Glass(rand() % 100));
            break;
        }
    // Note difference w/ chapter 14: Bins hold
    // exact type of object, not base type:
    vector<Glass*> glassBin;
    vector<Paper*> paperBin;
    vector<Aluminum*> alBin;
    vector<Trash*>::iterator sorter = bin.begin();
    // Sort the Trash:
    while (sorter != bin.end()) {
        Aluminum* ap =
            dynamic_cast<Aluminum*>(*sorter);
        Paper* pp =
            dynamic_cast<Paper*>(*sorter);
        Glass* gp =
            dynamic_cast<Glass*>(*sorter);
        if (ap) alBin.push_back(ap);
        if (pp) paperBin.push_back(pp);
        if (gp) glassBin.push_back(gp);
        sorter++;
    }
    sumValue(alBin, out);
    sumValue(paperBin, out);
    sumValue(glassBin, out);
    sumValue(bin, out);
    purge(bin);
} ///:~
